<script>
import store from "../../store/index.js";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import "@wangeditor/editor/dist/css/style.css";
import { CirclePlus, Delete } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import request from "../../utils/Request.js";
import { CONSTANT } from "../../constant/constant.js";

export default {
  name: "AddMockDialog",
  components: { Delete, CirclePlus, Editor, Toolbar, ElMessage },
  setup() {
    // 编辑器实例，必须用 shallowRef
    const editorRef = shallowRef();

    const editorConfig = {
      placeholder: "请输入Mock.mock(template)中的模板template，用{}包裹",
    };
    editorConfig.hoverbarKeys = {
      link: {
        menuKeys: [],
      },
      image: {
        menuKeys: [],
      },
      pre: {
        menuKeys: [],
      },
      table: {
        menuKeys: [],
      },
      divider: {
        menuKeys: [],
      },
      video: {
        menuKeys: [],
      },
      text: {
        menuKeys: [],
      },
    };
    const toolbarConfig = {};
    toolbarConfig.insertKeys = {
      index: 0, // 插入的位置，基于当前的 toolbarKeys
      keys: [
        "TemplateTextMenu",
        "StringTemplateMenu",
        "NumberTemplateMenu",
        "BoolTemplateMenu",
        "ObjectTemplateMenu",
        "ArrayTemplateMenu",
        "|",
        "PlaceholderTextMenu",
        "BoolPlaceholderMenu",
        "NumberPlaceholderMenu",
        "ArrayPlaceholderMenu",
        "StringPlaceholderMenu",
        "TimePlaceholderMenu",
        "ImagePlaceholderMenu",
        "ColorPlaceholderMenu",
        "NamePlaceholderMenu",
        "WebPlaceholderMenu",
        "AddressPlaceholderMenu",
        "IdPlaceholderMenu",
      ],
    };
    toolbarConfig.excludeKeys = [
      "headerSelect",
      "blockquote",
      // "|",
      "bold",
      "underline",
      "italic",
      "group-more-style",
      "color",
      "bgColor",
      "fontSize",
      "fontFamily",
      "lineHeight",
      "bulletedList",
      "numberedList",
      "todo",
      "group-justify",
      "group-indent",
      "emotion",
      "insertLink",
      "group-image",
      "group-video",
      "insertTable",
      "codeBlock",
      "divider",
      "undo",
      "redo",
      // "fullScreen"
    ];

    const valueHtml = "";

    // 组件销毁时，也及时销毁编辑器
    onBeforeUnmount(() => {
      const editor = editorRef.value;
      if (editor == null) return;
      editor.destroy();
    });

    const handleCreated = (editor) => {
      editorRef.value = editor; // 记录 editor 实例，重要！
    };

    return {
      editorRef,
      valueHtml,
      mode: "default", // 或 'simple'
      toolbarConfig,
      editorConfig,
      handleCreated,
    };
  }, // setup
  computed: {
    store() {
      return store;
    },
    ElMessage() {
      return ElMessage;
    },
    addMockDialogVisible() {
      return store.state.addMockDialogVisible;
    },
    isAdd() {
      return store.state.addMock.id === undefined;
    },
    BASE_URL() {
      if (store.state.user == null) {
        return CONSTANT.MOCK_BASE_URL + "{id}";
      }
      return CONSTANT.MOCK_BASE_URL + store.state.user.id;
    },
  },
  watch: {
    addMockDialogVisible(newVal, oldVal) {
      if (newVal === true) {
        this.valueHtml = store.state.addMock.template;
      }
    },
  },
  data() {
    return {
      // BASE_URL: CONSTANT.MOCK_BASE_URL + store.state.user.id,
      responseCodeList: [
        "101  Switching Protocols",
        "200  OK",
        "201  Created",
        "202  Accepted",
        "203  Non-Authoritative Information",
        "204  No Content",
        "205  Reset Content",
        "100  Continue",
        "206  Partial Content",
        "207  Multi-Status",
        "208  Already Reported",
        "226  IM Used",
        "300  Multiple Choices",
        "301  Moved Permanently",
        "302  Found",
        "303  See Other",
        "304  Not Modified",
        "305  Use Proxy",
        "306  Unused",
        "307  Temporary Redirect",
        "308  Permanent Redirect",
        "400  Bad Request",
        "401  Unauthorized",
        "402  Payment Required",
        "403  Forbidden",
        "404  Not Found",
        "405  Method Not Allowed",
        "406  Not Acceptable",
        "407  Proxy Authentication Required",
        "408  Request Time-out",
        "409  Conflict",
        "410  Gone",
        "411  Length Required",
        "412  Precondition Failed",
        "413  Request Entity Too Large",
        "414  Request-URI Too Large",
        "415  Unsupported Media Type",
        "416  Requested range not satisfiable",
        "417  Expectation Failed",
        "422  Unprocessable Entity",
        "423  Locked",
        "424  Failed Dependency",
        "426  Upgrade Required",
        "428  Precondition Required",
        "429  Too Many Requests",
        "431  Request Header Fields Too Large",
        "500  Internal Server Error",
        "501  Not Implemented",
        "502  Bad Gateway",
        "503  Service Unavailable",
        "504  Gateway Timeout",
        "505  HTTP Version Not Supported",
        "506  Variant Also Negotiates",
        "507  Insufficient Storage",
        "508  Loop Detected",
        "510  Not Extended",
        "511  Network Authentication Required",
      ],
      methodList: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
      rules: {
        name: [
          {
            required: true,
            message: "请给这个Mock配置取个名字",
            trigger: "blur",
          },
          { min: 1, max: 64, message: "你这个名字有点长啊", trigger: "blur" },
        ],
        path: [
          { required: true, message: "请填写请求路径", trigger: "blur" },
          {
            validator: (rule, value, callback) => {
              if (!new RegExp("^/[a-zA-Z0-9-_]+$").test(value)) {
                callback(new Error("请输入以/开头的请求路径"));
              } else callback();
            },
            trigger: "blur",
          },
        ],
        method: [
          { required: true, message: "请填写请求方式", trigger: "blur" },
          {
            validator: (rule, value, callback) => {
              if (!this.methodList.includes(value)) {
                callback(new Error("请选择正确的请求方式"));
              } else callback();
            },
            trigger: "blur",
          },
        ],
        responseCode: [
          { required: true, message: "请选择响应码", trigger: "blur" },
          { type: "number", message: "请选择正确的响应码", trigger: "blur" },
        ],
        responseHeaders: [
          {
            required: true,
            message: "请输入响应头参数，或者点击右侧删除",
            trigger: "blur",
          },
        ],
        template: [
          { required: true, message: "请填写Mock配置", trigger: "blur" },
          {
            validator: (rule, value, callback) => {
              if (
                store.state.addMock.template[0] !== "{" ||
                store.state.addMock.template[
                  store.state.addMock.template.length - 1
                ] !== "}"
              ) {
                callback(new Error("请输入正确的Mock模板"));
              } else callback();
            },
            trigger: "blur",
          },
        ],
      },
    };
  },
  methods: {
    onCloseDialog() {
      store.state.addMock = {
        name: "",
        path: "",
        method: "GET",
        template: "",
        responseCode: 200,
        responseHeaders: [],
      };
      this.valueHtml = "";
    },
    createMock() {
      let form = this.$refs["formRef"];
      let temp = {};

      store.state.addMock.template = this.valueHtml
        .replace(/<[^>]+>/g, "")
        .replace("&nbsp;", "")
        .trim();
      Object.assign(temp, store.state.addMock);

      temp.name = temp.name.trim();
      temp.path = temp.path.trim();
      temp.responseHeaders = JSON.stringify(temp.responseHeaders);

      form.validate((isValid) => {
        if (isValid) {
          if (this.isAdd)
            request({
              url: "/api/mock/mock/create",
              method: "post",
              data: temp,
            }).then(({ data }) => {
              if (data.code === 0) {
                store.state.addMockDialogVisible = false;
                ElMessage.success("创建成功");
                store.state.mocks.unshift({
                  id: data.data,
                  name: temp.name,
                  method: temp.method,
                  path: temp.path,
                });
              } else {
                ElMessage.error(data.msg);
              }
            });
          else
            request({
              url: "/api/mock/mock/update",
              method: "post",
              data: temp,
            }).then(({ data }) => {
              if (data.code === 0) {
                store.state.addMockDialogVisible = false;
                ElMessage.success("修改成功");
                for (let i = 0; i < store.state.mocks.length; i++) {
                  let mock = store.state.mocks.at(i);
                  if (mock.id === temp.id) {
                    store.state.mocks[i].name = temp.name;
                    store.state.mocks[i].method = temp.method;
                    store.state.mocks[i].path = temp.path;
                    break;
                  }
                }
              } else {
                ElMessage.error(data.msg);
              }
            });
        }
      });
    },
  },
};
</script>

<template>
  <el-dialog
    v-model="store.state.addMockDialogVisible"
    :title="isAdd ? '创建Mock' : '修改Mock'"
    destroy-on-close
    @close="onCloseDialog"
  >
    <el-form
      ref="formRef"
      :model="store.state.addMock"
      :rules="rules"
      class="ml-50 mr-50"
      :label-width="80"
    >
      <el-form-item label="名称" prop="name">
        <el-input
          type="text"
          v-model="store.state.addMock.name"
          placeholder="给接口取个名字吧"
        />
      </el-form-item>

      <el-form-item label="路径" prop="path">
        <el-input
          type="text"
          v-model="store.state.addMock.path"
          placeholder="以/开头的请求路径"
        >
          <template #prepend>{{ BASE_URL }}</template>
        </el-input>
      </el-form-item>

      <el-form-item label="请求方法" prop="method">
        <el-select v-model="store.state.addMock.method">
          <el-option
            v-for="item in methodList"
            :key="item"
            :label="item"
            :value="item"
          />
        </el-select>
      </el-form-item>

      <el-form-item label="响应码" prop="responseCode">
        <el-select v-model="store.state.addMock.responseCode">
          <el-option
            v-for="(item, index, code) in responseCodeList"
            :key="(code = item.split(' ')[0])"
            :label="item"
            :value="code"
          />
        </el-select>
      </el-form-item>

      <el-form-item label="响应头">
        <el-row>
          <el-col :span="24">
            <el-button
              plain
              text
              @click="
                store.state.addMock.responseHeaders.length < 20
                  ? store.state.addMock.responseHeaders.push({
                      header: '',
                      value: '',
                    })
                  : ElMessage.warning('20个Header应该够了吧兄弟？')
              "
            >
              <el-icon size="large">
                <CirclePlus />
              </el-icon>
            </el-button>
          </el-col>
        </el-row>
      </el-form-item>

      <el-form-item
        v-for="(item, index) in store.state.addMock.responseHeaders"
        style="width: 100%"
        prop="responseHeaders"
      >
        <el-row :gutter="10" style="width: 100%">
          <el-col :span="11">
            <el-input v-model="item.header" placeholder="参数名称" />
          </el-col>
          <el-col :span="11">
            <el-input v-model="item.value" placeholder="参数值" />
          </el-col>
          <el-col :span="2">
            <el-button
              text
              plain
              @click="store.state.addMock.responseHeaders.splice(index, 1)"
            >
              <el-icon>
                <Delete />
              </el-icon>
            </el-button>
          </el-col>
        </el-row>
      </el-form-item>

      <el-form-item label="响应内容" prop="template">
        <div style="border: 1px solid #ccc; width: 100%">
          <Toolbar
            style="border-bottom: 1px solid #ccc"
            :editor="editorRef"
            :defaultConfig="toolbarConfig"
            :mode="mode"
          />
          <Editor
            style="height: 350px; overflow-y: hidden"
            v-model="valueHtml"
            :defaultConfig="editorConfig"
            :mode="mode"
            @onCreated="handleCreated"
          />
        </div>
      </el-form-item>
    </el-form>

    <template #footer>
      <el-button @click="store.state.addMockDialogVisible = false"
        >取消</el-button
      >
      <el-button type="primary" @click="createMock">
        {{ isAdd ? "创建" : "修改" }}
      </el-button>
    </template>
  </el-dialog>
</template>

<style scoped>
</style>